Transactions are logical groups of commands that are
committed to the database or rolled back in the database at the same
time. This allows you to insert, update, and delete several different
tables and revert those changes if a single command within the
transaction fails, or commit all the work if there are no errors. You
can control the locking that SQL Server takes on the tables used within
the transaction by changing the transaction isolation level. There are
a few myths about transactions that are important to know are not true:
If a single command within your transaction fails then none of the data will be written.
This is incorrect. If you don’t have any error catching that causes the
transaction to be rolled back then the statements that were successful
will be committed when the COMMIT statement is issued.
A stored procedure is automatically a transaction.
This is also incorrect. Each statement within the stored procedure is
executed within its own autocommitted transaction, but the stored
procedure as a whole is not an autocommitted transaction. If you want
the entire context of the stored procedure to be executed within a
single transaction then you will need to explicitly define a
transaction within the stored procedure.
If a statement fails then the transaction will roll back.
That isn’t going to happen either. If a command fails and there is no
logic to roll back the transaction then the transaction will continue
and commit the data when it gets to the COMMIT statement.
If I create a transaction and run a select statement no one else can access the rows.
This is sort of true. Depending on the transaction isolation (read on
for more information) of the person running the select statement this
may or may not be true. If you are using the default isolation level of
READ_COMMITED then this statement is true. If the SELECT statement has been issued under the READ_UNCOMMITED isolation level then this statement is not true.
There are two kinds of transactions available to you as a programmer. There are local transactions that are defined with the BEGIN TRANSACTION
statement. These local transactions are used for statements that are
going to be within the scope of the local database instance. The BEGIN TRANSACTION statement can be abbreviated as BEGIN TRAN.
There are also distributed transactions that are defined with the BEGIN DISTRIBUTED TRANSACTION
statement. These distributed transactions are used when statements
within the transaction must go beyond the scope of the instance. This
is most often done via a query or stored procedure execution between
instances of SQL Server through a linked server. This can also be done
via an OPENROWSET
call. In order for distributed transactions to work a transaction is
created on all the servers that are involved in the transaction and are
kept in sync by the use of the distributed transaction coordinators
(MSDTC in the case of SQL Server) that must be installed on all the
servers involved in the transaction. The BEGIN DISTRIBUTED TRANSACTION statement can be abbreviated as BEGIN DISTRIBUTED TRAN.
Distributed
transactions can be created against database platforms other than
Microsoft SQL Server. Both Oracle and DB2 have distributed transaction
coordinators that can be configured and work with the MSDTC service
that SQL Server uses.
MSDTC
does not come configured for server to server distributed transactions
on Windows 2003 or Windows 2008. Although the configuration of MSDTC is
beyond the scope of this book, knowledge of the fact that it needs to
be configured is necessary.
There are three kinds of transactions within SQL Server. There are explicit transactions, which are transactions where the BEGIN TRANSACTION, ROLLBACK, and COMMIT
statements are explicitly used within the T/SQL code. There are
autocommit transactions, which are what each T/SQL statement is by
default. An autocommit transaction does not require the use of BEGIN TRANSACTION, ROLLBACK, or COMMIT statements. The third kind of transaction is the implicit transaction. Implicit transactions are enabled by using the SET IMPLICIT_TRANSACTIONS
statement and setting it to ON. The transaction will then be started
when the next statement is executed. The transaction will continue
until a COMMIT or ROLLBACK
statement is issued. After the transaction is committed or rolled back
when the next statement is executed a new transaction will be started.
Named Transactions
Named
transactions are transactions that have a specific name assigned to
them. Transactions are typically named so that you can more easily
identify which transaction you are rolling forward or backward within
the T/SQL code. Naming transactions also makes it easier to know which
transactions within a stored procedure are causing locking and blocking.
All
transactions within Microsoft SQL Server are technically named
transactions. By default each transaction that does not have a name
assigned to it is given the name user_transaction. Transactions are named within the BEGIN TRANSACTION command by simply specifying the name of the transaction on the same line.
BEGIN TRANSACTION YourTransactionName
...
COMMIT TRNASACTION YourTransactionName
The
name of the transaction must conform to the normal SQL Server naming
convention, but be no longer than 32 characters in length. The
transaction name can be a variable, but the variable must be declared
as a char, varchar, nchar, or nvarchar data type.
Exercise . Create a Named Transaction
Use the BEGIN TRANSACTION command to create a transaction named SampleUpdate, and update some data in the AdventureWorks database. Roll the transaction back and see that the data was not updated. Rerun
the command this time committing the transaction again, and viewing
that the data has been changed. A sample update statement has been
provided. UPDATE Person.Contact SET LastName = 'Jones' WHERE ContactID = 8
|
In
addition to naming your transaction, you can also place a mark in the
transaction log with a description. This is done by adding the WITH MARK option to the BEGIN TRANSACTION
statement. This allows you to place a description of the transaction
within SQL Server transaction log. This allows you to restore the
database to a specific transaction mark. The transaction mark is stored
in the logmarkhistory table of the MSDB database.
BEGIN TRNASACTION YourTransactionName WITH MARK 'Doing something in a
transaction'
...
COMMIT TRANSACTION YourTransactionName
The
description of the mark can be any valid string of characters up to 255
characters when using a Unicode string. If you are using a non-Unicode
string then the mark can be up to 510 characters.
Nesting
Transaction
nesting is a technique where you can control within a single parent
transaction several smaller groups of commands that are committed or
rolled back independently. Each nested or inner transaction must be
committed independently of the parent or outer transaction. The parent
transaction must also be committed in order for the data to be
committed to the database. If the inner transactions are committed and
the outer transaction is rolled back, then the inner transaction will
be rolled back. If the inner transactions are rolled back and the outer
transaction is committed, then the inner transactions are rolled back
and any commands within the outer transaction that are not within the
inner transactions are committed and written to the database.
BEGIN TRANSACTION Parent1
UPDATE ...
BEGIN TRNASACTION Child1
...
COMMIT TRANSACTION Child1
UPDATE ...
BEGIN TRANSACTION Child2
...
COMMIT TRANSACTION Child2
IF @SomeVariable = 0
ROLLBACK TRANSACTION Parent1
ELSE
COMMIT TRANSACTION Parent1
COMMIT and ROLLBACK
COMMIT and ROLLBACK
are the statements used to tell SQL Server engine that the transaction
has been completed and whether the transaction has been completed
successfully or not. If the transaction was successful and the data
should be written to disk then the COMMIT statement should be used. If there was a problem and the data should not be written to the database then the ROLLBACK statement should be used.
You
have to be careful when rolling back transactions. If you have a failed
transaction and you write error data to an error table, then roll back
your transaction,
the writing of the error data to that error table will also be rolled
back. Temporary tables are also controlled by your transaction, so
writing your error data to a temporary table will not get you past
this; however, data in a table variable will persist through a rollback
allowing you to write the data from the table variable to the error
table after the rollback has been completed.
DECLARE @ErrorData TABLE (ErrorNumber INT, ErrorMessage NVARCHAR(MAX))
BEGIN TRANSACTION Test1
BEGIN TRY
...
END TRY
BEGIN CATCH
INSERT INTO @ErrorData
SELECT ERROR_NUMBER(), ERROR_MESSAGE()
END CATCH
IF EXISTS (SELECT * FROM @ErrorData)
ROLLBACK TRANSACTION Test1
ELSE
COMMIT TRANSACTION Test1
INSERT INTO ActualErrorTable
SELECT ErrorNumber, ErrorMessage
FROM @ErrorData
You can use the XACT_STATE
system function to determine the state of the current transaction. This
function returns three possible values: 1, 0, and –1. A value of 1
means that a healthy committable transaction is in process. A value of
0 means that there is no transaction running. A value of –1 means that
the transaction is in such a state that it must be completely rolled
back. A value of –1 tells you that the transaction cannot be committed,
nor can it be rolled back to any transaction save point.
Normally
if a single statement within the transactions fails, the transactions
continue, unless the state of the failure is critical enough that the
entire batch is killed. This normal process of continuing the
transaction can be overridden by setting the XACT_ABORT
setting to ON. This setting tells SQL Server that if any statement
fails then the database engine should roll back the entire transaction.
This setting defaults to OFF.
When writing to another database server over a linked server against an OLE DB provider the XACT_ABORT
needs to be set to ON. The exception to this is if the OLE DB provider
supports nested transactions. If the provider supports nested
transactions you can set the XACT_ABORT to either ON or OFF.
Save Points
Save
points are special optional markers within a transaction. These markers
allow you to roll back from the current location to the named save
point, leaving the commands prior to the save point committed to the
database. All save points are named, and duplicate names are allowed,
but if you reuse the save point name within the transaction and the
transaction is rolled back, the transaction is rolled back to the
latest save point of that name.
BEGIN TRANSACTION
UPDATE Table1 ...
SAVE TRANSACTION Point1
UPDATE Table2 ...
SAVE TRANSACTION Point2
COMMIT
An
important note with save points is that save points cannot be used in
distributed transactions. This includes explicit transactions that are
started with the BEGIN DISTRIBUTED TRANSACTION or explicit distributed transactions, which are escalated automatically from a local transaction to a distributed transaction.